package ph.com.gs3.formalistics.service.services;

import java.util.List;

import ph.com.gs3.formalistics.global.constants.ApplicationConfigs;
import ph.com.gs3.formalistics.global.constants.ApplicationConfigs.ApplicationMode;
import ph.com.gs3.formalistics.global.utilities.logging.FLLogger;
import ph.com.gs3.formalistics.global.utilities.services.ServiceEventNotifierUtility;
import ph.com.gs3.formalistics.model.communicators.CommentCommunicatorModule;
import ph.com.gs3.formalistics.model.communicators.HttpCommunicator;
import ph.com.gs3.formalistics.model.dao.CommentsDAO;
import ph.com.gs3.formalistics.model.dao.DocumentsDAO;
import ph.com.gs3.formalistics.model.dao.FormsDAO;
import ph.com.gs3.formalistics.model.dao.UserAccountsDAO;
import ph.com.gs3.formalistics.model.valueobjects.business.Comment;
import ph.com.gs3.formalistics.model.valueobjects.business.User;
import ph.com.gs3.formalistics.model.valueobjects.business.document.DocumentStub;
import ph.com.gs3.formalistics.model.valueobjects.business.form.FormStub;
import ph.com.gs3.formalistics.presenter.MainActivity;
import ph.com.gs3.formalistics.service.managers.CommentManager;
import ph.com.gs3.formalistics.service.managers.CommentManager.DownloadCommentsFailedException;
import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;

public class CommentsUpdateService extends IntentService {

	// =========================================================================
	// {{ Constants

	public static final String TAG = CommentsUpdateService.class.getSimpleName();

	public static final String NAME = CommentsUpdateService.class.getName();

	public static final String ACTION_ON_UPDATE_STARTED = NAME + "_update_start";
	public static final String ACTION_ON_UPDATE_DONE = NAME + "_update_done";

	public static final String ACTION_ON_DOCUMENT_COMMENTS_UPDATED = NAME
	        + "_document_comments_updated";

	public static final String EXTRA_CURRENT_USER = "current_user";

	public static final int UPDATE_READ_TIMEOUT_DEV = 3000; // 3s
	public static final int UPDATE_READ_TIMEOUT = 30000; // 30s

	// }}

	// =========================================================================
	// {{ Dependencies

	private UserAccountsDAO userAccountsDAO;
	private FormsDAO formsDAO;
	private DocumentsDAO documentsDAO;
	private CommentsDAO commentsDAO;

	private CommentCommunicatorModule commentCommunicatorModule;

	private CommentManager commentManager;

	// }}

	public CommentsUpdateService() {
		super(TAG);
	}

	@Override
	protected void onHandleIntent(Intent intent) {

		// initialize parameters
		Bundle extras = intent.getExtras();

		User currentUser = (User) extras.getSerializable(EXTRA_CURRENT_USER);

		// notify
		Bundle notificationExtras = new Bundle();
		notificationExtras.putSerializable(MainActivity.EXTRA_LOGGED_IN_USER, currentUser);

		ServiceEventNotifierUtility.getDefaultInstance().displayNotificationWithProgress(this,
		        ServiceEventNotifierUtility.NOTIFICATION_ID_PRIMARY, "Syncing comments", 0, 0,
		        true, notificationExtras);

		initializeDependencies(currentUser);

		// service start

		broadcastServiceStarted();

		String server = currentUser.getAccountServer();
		String companyid = currentUser.getCompanyId();

		// =================================================================================
		// synch deleted comments

		commentManager.deleteCommentsDeletedFromServer();

		// =================================================================================
		// get new comments

		// get all the forms and their documents
		formsDAO.open();
		List<FormStub> forms = formsDAO.getAllCompanyFormStubs(server, companyid);
		formsDAO.close();

		for (FormStub form : forms) {

			FLLogger.d(TAG, "Updating comments from form: " + form.name);

			documentsDAO.open();
			List<DocumentStub> documentStubs = documentsDAO
			        .getFormDocumentStubs(server, form.webId);
			documentsDAO.close();

			String[] documentIdList = getDocumentIdListFromStubs(documentStubs);

			String lastCommentsUpdate = form.lastCommentSearchUpdateDate;

			List<Comment> newComments = null;

			try {
				// throws DownloadCommentsFailedException
				newComments = commentManager.downloadNewCommentsAndUsers(form.webId,
				        documentIdList, lastCommentsUpdate, 0, 500);

			} catch (DownloadCommentsFailedException e) {
				e.printStackTrace();

				// TODO: add a connection test here, if the connection is available, try
				// downloading again later, otherwise stop the whole process.

				// TODO: add a record of failure here so that the application may retry
				// again later.
			}

			// update the form last update if there are new comments
			if (newComments != null && newComments.size() > 0) {
				Comment latestComment = newComments.get(0);
				String lastestUpdate = latestComment.getDateCreated();

				// save the last update date of the comments
				formsDAO.open();
				formsDAO.setCommentsLastUpdateDate(server, form.webId, lastestUpdate);
				formsDAO.close();
			}

		}

		ServiceEventNotifierUtility.getDefaultInstance().dismissPrimaryNotification(this);

		broadcastServiceDone();
	}

	private String[] getDocumentIdListFromStubs(List<DocumentStub> documentStubs) {

		int documentCount = documentStubs.size();
		String[] documentIdList = new String[documentCount];

		for (int i = 0; i < documentCount; i++) {
			documentIdList[i] = documentStubs.get(i).webId;
		}

		return documentIdList;

	}

	private void initializeDependencies(User currentUser) {

		userAccountsDAO = new UserAccountsDAO(getApplicationContext());
		formsDAO = new FormsDAO(getApplicationContext());
		documentsDAO = new DocumentsDAO(getApplicationContext());
		commentsDAO = new CommentsDAO(getApplicationContext());

		ApplicationMode mode = ApplicationConfigs.APPLICATION_MODE;

		// Create a communicator that has a long read timeout since we will be reading
		// bulks of data from the server.
		HttpCommunicator communicator = new HttpCommunicator();
		communicator.setReadTimeout(mode == ApplicationMode.DEVELOPMENT ? UPDATE_READ_TIMEOUT_DEV
		        : UPDATE_READ_TIMEOUT);

		commentCommunicatorModule = new CommentCommunicatorModule(communicator,
		        currentUser.getAccountServer());

		commentManager = new CommentManager(userAccountsDAO, commentsDAO, commentCommunicatorModule);

	}

	// ========================================================================
	// {{ Broadcast Methods

	private void broadcastServiceStarted() {

		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_UPDATE_STARTED);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
		sendBroadcast(broadcastIntent);

	}

	private void broadcastServiceDone() {

		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_UPDATE_DONE);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
		sendBroadcast(broadcastIntent);

	}

	// }}

}
